#pragma once

#include<vector>
#include<semaphore.h>


namespace RingQueue
{
    #define DEF_CAP 10

    template<class T>
    class RingQueue
    {
    public:
        RingQueue(size_t cap=DEF_CAP)
        :_cap(cap),_con_step(0),_pro_step(0)
        {
            _queue.resize(_cap);

            sem_init(&_pro_sem,0,_cap);
            sem_init(&_con_sem,0,0);

            pthread_mutex_init(&_pro_mutex,nullptr);
            pthread_mutex_init(&_con_mutex,nullptr);
        }
        ~RingQueue()
        {
            sem_destroy(&_pro_sem);
            sem_destroy(&_con_sem);

            pthread_mutex_destroy(&_pro_mutex);
            pthread_mutex_destroy(&_con_mutex);
        }

        void Push(const T& inDate)
        {
            P(&_pro_sem);
            Lock(&_pro_mutex);


            _queue[_pro_step++]=inDate;
            _pro_step%=_cap;

            UnLock(&_pro_mutex);
            V(&_con_sem);
        }

        void Pop(T* outDate)
        {
            P(&_con_sem);

            Lock(&_con_mutex);
            *outDate=_queue[_con_step++];
            _con_step%=_cap;
            UnLock(&_con_mutex);
            V(&_pro_sem);
        }

    private:
    void P(sem_t *sem)
    {
        sem_wait(sem);
    }
    void V(sem_t *sem)
    {
        sem_post(sem);
    }
    void Lock(pthread_mutex_t* lock)
    {
        pthread_mutex_lock(lock);
    }
    void UnLock(pthread_mutex_t* lock)
    {
        pthread_mutex_unlock(lock);
    }
    private:
        std::vector<T> _queue;
        size_t _cap;
        sem_t _con_sem;
        sem_t _pro_sem;
        size_t _con_step;
        size_t _pro_step;
        
        pthread_mutex_t _pro_mutex;
        pthread_mutex_t _con_mutex;
    };
}